package com.zpc.rabbitmq.config;

import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.zpc.rabbitmq.mqcallback.MsgSendConfirmCallBack;
import com.zpc.rabbitmq.mqcallback.MsgSendReturnCallback;

/**
 * 队列和交换机配置 绑定
 * 
 * @author Dhjie
 *
 */
@Configuration
public class MqConfig {

	/**
	 * 队列
	 */
	public static final String QUEUE_NAME = "queue_test_001";

	public static final String QUEUE_TEST_NAME = "queue_test_002";

	public static final String QUEUE_TEST_FANOUT001 = "queue_fanout_001";

	public static final String QUEUE_TEST_FANOUT002 = "queue_fanut_002";

	/**
	 * 交换机
	 */
	public static final String EXCAHNGE_NAME = "excahange_test_001";

	public static final String EXCAHNGE_FANOUT_NAME = "excahange_test_fanout";
	@Autowired
	private ExchangeConfig exchangeConfig;
	@Autowired
	private QueueConfig queue;
	/**
	 * 连接工厂
	 */
	@Autowired
	private org.springframework.amqp.rabbit.connection.ConnectionFactory connectionFactory;

	/**
	 * 绑定  路由模式   交换机
	 * 
	 * @return
	 */
	@Bean
	public Binding testExchange() {
		return BindingBuilder.bind(queue.testQueue()).to(exchangeConfig.testExchange()).with(MqConfig.QUEUE_NAME);
	}

	@Bean
	public Binding testExchange001() {
		return BindingBuilder.bind(queue.testQueue001()).to(exchangeConfig.testExchange001()).with(MqConfig.QUEUE_TEST_NAME);
	}

	/**
	 * 绑定 订阅模式（广播模式） 交换机	
	 * @param queueFanout001
	 * @param fanoutExchange
	 * @return
	 */
	@Bean
	public Binding fanoutExchange001(@Qualifier("queueFanout001") Queue queueFanout001,FanoutExchange fanoutExchange) {
		return BindingBuilder.bind(queueFanout001).to(fanoutExchange);
	}

	@Bean
	Binding fanoutExchange002(@Qualifier("queueFanout002") Queue queueFanout002,FanoutExchange fanoutExchange) {
		return BindingBuilder.bind(queueFanout002).to(fanoutExchange);
	}
	/**
	 * 定制一些处理策略 定制化amqp模板
	 * 
	 * @return
	 */
	@Bean
	public SimpleMessageListenerContainer simpleMessageListenerContainer() {
		SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
		// 设置确认模式为手动模式
		container.setAcknowledgeMode(AcknowledgeMode.MANUAL);
		container.setExposeListenerChannel(true);
		container.setAutoStartup(false);
		container.setMaxConcurrentConsumers(500);
		container.setConcurrentConsumers(1);
		return container;
	}

	/**
	 * 定义rabbit template用于数据的接收和发送
	 *
	 * @return
	 */
	@Bean
	public RabbitTemplate rabbitTemplate() {
		RabbitTemplate template = new RabbitTemplate(connectionFactory);
		/**
		 * 若使用confirm-callback或return-callback，
		 * 必须要配置publisherConfirms或publisherReturns为true
		 * 每个rabbitTemplate只能有一个confirm-callback和return-callback
		 */
		template.setConfirmCallback(msgSendConfirmCallBack());
		template.setReturnCallback(msgSendReturnCallback());

		/**
		 * 使用return-callback时必须设置mandatory为true，或者在配置中设置mandatory-expression的值为true，
		 * 可针对每次请求的消息去确定’mandatory’的boolean值， 只能在提供’return -callback’时使用，与mandatory互斥
		 */
		template.setMandatory(true);

		return template;
	}

	/**
	 * 消息确认机制 Confirms给客户端一种轻量级的方式，能够跟踪哪些消息被broker处理， 哪些可能因为broker宕掉或者网络失败的情况而重新发布。
	 * 确认并且保证消息被送达，提供了两种方式：发布确认和事务。(两者不可同时使用)
	 * 在channel为事务时，不可引入确认模式；同样channel为确认模式下，不可使用事务。
	 *
	 * @return
	 */

	@Bean
	public RabbitTemplate.ConfirmCallback msgSendConfirmCallBack() {
		return new MsgSendConfirmCallBack();
	}

	@Bean
	public RabbitTemplate.ReturnCallback msgSendReturnCallback() {
		return new MsgSendReturnCallback();
	}
}
